package com.blankland.dataanalysis.utls;

import com.baomidou.mybatisplus.annotation.TableField;
import com.blankland.dataanalysis.domain.SpectrumData;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 现场测量与高纯锗测量转换函数
 */
public class DataAnalysisUtil {


    /**
     *
     * 所有的数据数据全是一列一列的，
     * CharVal=
     *  lng     ...
     *  lat     ...
     *  val1    ...
     *  val2    ...
     *  val3    ...
     *    ...
     *  val18   ...
     *
     *
     * @param spectrum 原始谱线数据
     * @param lng   经度
     * @param lat   纬度
     * @return   经度，纬度，18个特征向量
     */
    /**
     * @param k        能量转成道址的参数k
     * @param b        能量转成道址的参数b
     * @param spectrum 原始谱线数据（一列一列的）
     * @param lng      经度
     * @param lat      维度
     * @return
     */
    public static double[][] NaI2HPGeCharVal(double k, double b, int[][] spectrum, double[] lng, double[] lat) {
        /**
         * 1 根据K40固定能量，Ti208固定能量，仪器上显示的K40道址和仪器上显示的Ti208道址，计算出该台设备的私有属性k和b
         *   使用k和b，计算出该台设备的道址划分区间
         */
        // 1.1、18个特征向量对应的能量（固定的）
        double[] energy = {609.7095, 707.189, 631.721, 697.7555, 707.189, 738.634, 675.744, 832.969, 751.212, 823.5355, 766.9345, 873.8475, 848.6915, 977.616, 905.2925, 999.6275, 911.5815, 1027.928, 961.8935, 1037.3615, 1087.6735, 1200.8755, 1147.419, 1210.309, 1213.4535, 1314.0775, 1235.465, 1354.956, 1329.8, 1443.002, 1392.69, 1531.048, 1700.851, 1814.053, 2562.444, 2678.7905};
        // 1.2、使用k和b计算出该台设备的道址（每台设备私有的道址属性PeakCh）
        int[] PeakCh = new int[36];
        for (int i = 0; i < energy.length; i++) {
            PeakCh[i] = (int) ((energy[i] - b) / k);
        }

        System.out.println("峰边界:"+Arrays.toString(PeakCh));


        /**
         * 2 使用实验室化验大河湾的放射性元素数据，计算出200条数据的均值和标准差
         */
        //18个特性向量的均值

        double[] HPGe_Mu = {57.60437293,31.20768187,47.87861707,301.5118793,102.5777344,245.9150581,322.5151406,332.5097882,440.9607958,	184.0715178,	424.6661691,	222.1067616,	269.5667577,	707.0347321,	807.6384339,	2840.179566,	442.2150372,	1387.909794};
        //18个特征向量的标准差（无偏）
        double[] HPGe_Sigma = {5.5641126717353435, 4.657174298516674,10.195628314110712,29.16470500880574,20.029617612925232,34.711553892256234,23.77944485575649,31.211341946916882,56.391173639047835,29.316207300541357,38.19613277444575,26.064359586069095,35.8023486023348,57.08919129429344,64.73202670206571,161.59933321956285,46.167553603933236,95.52973271620284};


        /**
         * 3 以10个原始谱线数据为一组，确定返回解析数据的个数(几列数据)
         */
        int num = (int) (spectrum[0].length / 10);


        /**
         * 4 定义返回的数据
         */
        // 4.1 18个特征向量+经纬度的数组
        double[][] CharVal = new double[20][num];//(经度，纬度，特征值)
        // 4.2 谱线的均值
        double[] NaI_Mu = new double[18];
        // 4.3 谱线的标准差
        double[] NaI_Sigma = new double[18];

        /**
         * 5 解析数据
         */
        // 5.1 解析出来一共多少条数据
        for (int i = 0; i < num; i++) {
            double Lng_t = 0;//经度
            double Lat_t = 0;//纬度
            int[] CharVal_t = new int[18];//18个特征向量

            // 5.2 解析出来的一条数据 = 10条原始谱线数据
            for (int index = 0; index < 10; index++) {
                // 5.3 道址数据（2个为一组，一共18组）
                for (int j = 0; j < PeakCh.length; j += 2) {
                    // 5.4 计算每个道址范围内的所有数据（如第一组数据中的，217~247）
                    for (int kk = PeakCh[j]; kk <= PeakCh[j + 1]; kk++) {
                        // 5.5 18个特征向量 = spectrum[指定道址][10条原始谱线数据]
                        CharVal_t[j / 2] += spectrum[kk][i * 10 + index];
                    }
                }
                Lng_t += lng[index];
                Lat_t += lat[index];

            }

            // 5.6、将解析好的18个特征向量、经度、纬度填充到CharVal数组中
            for (int j = 2; j < 20; j++) {
                CharVal[j][i] = CharVal_t[j - 2] / 10.0;
            }
            CharVal[0][i] = Lng_t / 10;
            CharVal[1][i] = Lat_t / 10;

//            System.out.println("------------第"+i+"解析--------------");
//            for (double[] doubles : CharVal) {
//                System.out.println(Arrays.toString(doubles));
//            }

        }




        /**
         * 6 计算出原始谱线（10条）数据解析完成（1条）之后的18个特征值的均值和标准差
         */
        // 6.1 解析完成的谱线 18个特征向量的均值
        for (int j = 2; j < 20; j++) {
            for (int i = 0; i < num; i++) {  // i是解析完成谱线数据的个数
                NaI_Mu[j - 2] += CharVal[j][i]; // j是18个特征向量的值
            }
            NaI_Mu[j - 2] /= num;
        }
        System.out.println("均值："+Arrays.toString(NaI_Mu));
        // 6.2 解析完成的谱线 18个特征向量的标准差
        for (int j = 2; j < 20; j++) {
            for (int i = 0; i < num; i++) {
                //方差
                NaI_Sigma[j - 2] += Math.pow(NaI_Mu[j - 2] - CharVal[j][i], 2);
            }
            //标准差无偏估计
            //NaI_Sigma[j - 2] = Math.sqrt(NaI_Sigma[j - 2] / num);
            //标准差无偏估计
            NaI_Sigma[j - 2] = Math.sqrt(NaI_Sigma[j - 2] / (num-1));
        }
        System.out.println("标准差："+Arrays.toString(NaI_Sigma));

        /**
         * 7 使用实验室测量的均值+标准差 和 解析完成的均值+标准差进行映射
         */
        // 7.1 判断标准差中是否包含0
        for (int i = 0; i < num; i++) {
            // 7.2 每列数据的18个特征向量
            for (int j = 2; j < 20; j++) {
                if(NaI_Sigma[j - 2] == 0.0){
                    // 7.3 如果标准差中包含0，直接复制为样本中的均值
                    CharVal[j][i] = HPGe_Mu[j - 2];
                }else {
                    // 7.4 映射转换
                    CharVal[j][i] = ((CharVal[j][i] - NaI_Mu[j - 2]) / NaI_Sigma[j - 2] * HPGe_Sigma[j - 2] + HPGe_Mu[j - 2]);
                }
            }
        }


//        // 7.2 遍历列，解析完成有几条数据
//        for (int i = 0; i < num; i++) {
//            // 7.2 每列数据的18个特征向量
//            for (int j = 2; j < 20; j++) {
//                CharVal[j][i] = ((CharVal[j][i] - NaI_Mu[j - 2]) / NaI_Sigma[j - 2] * HPGe_Sigma[j - 2] + HPGe_Mu[j - 2]);
//            }
//        }


        return CharVal;
    }




}
